#include<stdio.h>

/*
int main()
{
    FILE* fp = fopen("./log.txt", "w");
    FILE* fp = fopen("./log.txt", "r");
    FILE* fp = fopen("./log.txt", "a");//追加(append)
    if(fp == NULL){
        perror("fopen");
        return 1;
    }

    while(fgets(buffer, sizeof(buffer), fp)){
    char buffer[64];
        printf("%s", buffer);
    }
    if(feof(fp)){
        printf("fgets quit not normal!\n");
    }
    else{
        printf("fgets quit normal!\n");
    }
    
    int cnt = 5;
    while(cnt--){
        const char* msg = "hello bit\n";
        fputs(msg, fp);
    }
    fclose(fp);
    return 0;
}
*/ 

/*
    如果学习文件只停留在语言层面上, 是很难对文件有很深的理解的
    C语言默认会打开三个输入输出流: stdin, stdout, stderr
    #include<stdio.h>
    extern FILE* stdin;
    extern FILE* stdout;
    extern FILE* stderr;
    可以看到这三个流在C语言看来, 就是三个文件

    在体系结构角度: 这三个流分别对应的硬件是
                    stdin  -> 键盘
                    stdout -> 显示器
                    stderr -> 显示器
*/


//int main()
//{
//    const char* msg = "you can see me!\n";
    
    /*
        stdout 和 stderr 的区别:
        若我们运行 ./myfile 时, 都能向显示器上打印
        但是如果我们 ./myfile > log.txt 时
        只有 stdout 的内容会重定向到 log.txt 中
        所以 > 是叫输出重定向, 只会把stdout的内容重定向到文件中
    */
//    fputs(msg, stdout);
//    fputs(msg, stderr);
    
//    return 0;
//}



/*
    无论什么语言, 对文件的操作最后都是对硬件访问
    OS 是硬件的管理者
    所以, 所有语言上对文件的操作, 都必须贯穿 OS!
    (见图1)
    操作系统不相信任何人, 访问操作系统必须通过系统调用接口
    所以所有的语言, 比如fopen, fclose, fwrite等在底层一定需要OS提供的系统调用

*/


/*
    #include<sys/type.h>
    #include<sys/stat.h>
    #include<fcntl.h>

    pathname: 文件路径
    flags: 文件打开方式
    mode: 设置文件权限等信息
    返回值: 返回一个文件描述符 fd
    int open(const char* pathname, int flags);
    int open(const char* pathname, int flags, mode_t mode);
    int creat(const char* pathname, mode_t mode);
*/

#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h> 

int main()
{
    // O_WRONLY: 写入   O_CREAT: 创建
    // 如果没有 0644 则文件的权限的是未知混乱的
    // 疑问:为什么 flag 类型是int, 却可以传递两个值
    //      传递标志位, int有32位, 一个bit表示一个标志
    //      O_WRONLY, O_RDONLY, O_CREAT 等都是只有一个bit位为一, 且不重复
    //      在传递时只需将多个标志按位或, 就得到了标志位
    int fd1 = open("./log1.txt", O_WRONLY | O_CREAT, 0644);
    int fd2 = open("./log2.txt", O_WRONLY | O_CREAT, 0644);
    int fd3 = open("./log3.txt", O_WRONLY | O_CREAT, 0644);
    if(fd1 < 0 || fd2 < 0 || fd3 < 0){
        printf("open error\n");
    }
    /*
        打印出来的文件描述符是: 3 4 5 
        疑问:0 1 2 去哪里呢?
        0: 标准输入->键盘
        1: 标准输出->显示器
        2: 标准错误->显示器

        看到 0, 1, 2, 3 你会联想到什么呢?
        !! 数组下标 !!
    */
    printf("%d\n", fd1);
    printf("%d\n", fd2);
    printf("%d\n", fd3);

    close(fd1);
    close(fd2);
    close(fd3);
    return 0;
}

/*
        所有的文件操作, 表现上都是进程执行对应的函数
        即进程对文件操作
        要操作文件必须打开文件, 即将文件相关的属性信息加载到内存中
        导致操作系统中存在大量的文件(进程:文件=1:n)
        故操作系统需要管理众多文件
        如何管理?  !!! 先描述, 在组织 !!!
        C语言如何描述呢?
        struct file{
            // 文件属性
            // 链接关系
        }
*/






